home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / aztecnos.arc / TCPSUBR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-19  |  7.2 KB  |  328 lines

  1. #include <stdio.h>
  2. #include "global.h"
  3. #include "timer.h"
  4. #include "mbuf.h"
  5. #include "netuser.h"
  6. #include "internet.h"
  7. #include "tcp.h"
  8.  
  9. void tcp_timeout(),tcp_msl(),link_tcb();
  10. extern char *Tcpstates[];
  11. static int16 hash_tcb();    
  12.  
  13. struct tcb *Tcbs[NTCB];
  14. int16 Tcp_mss = DEF_MSS;    /* Maximum segment size to be sent with SYN */
  15. int32 Tcp_irtt = DEF_RTT;    /* Initial guess at round trip time */
  16. int Tcp_trace;            /* State change tracing flag */
  17.  
  18. /* Lookup connection, return TCB pointer or NULLTCB if nonexistant */
  19. struct tcb *
  20. lookup_tcb(conn)
  21. struct connection *conn;
  22. {
  23.     register struct tcb *tcb;
  24.  
  25.     tcb = Tcbs[hash_tcb(conn)];
  26.     while(tcb != NULLTCB){
  27.         /* Yet another structure compatibility hack */
  28.         if(conn->local.address == tcb->conn.local.address
  29.          && conn->remote.address == tcb->conn.remote.address
  30.          && conn->local.port == tcb->conn.local.port
  31.          && conn->remote.port == tcb->conn.remote.port)
  32.             break;
  33.         tcb = tcb->next;
  34.     }
  35.     return tcb;
  36. }
  37.  
  38. /* Create a TCB, return pointer. Return pointer if TCB already exists. */
  39. struct tcb *
  40. create_tcb(conn)
  41. struct connection *conn;
  42. {
  43.     register struct tcb *tcb;
  44.  
  45.     if((tcb = lookup_tcb(conn)) != NULLTCB)
  46.         return tcb;
  47.     if((tcb = (struct tcb *)calloc(1,sizeof (struct tcb))) == NULLTCB)
  48.         return NULLTCB;
  49.     ASSIGN(tcb->conn,*conn);
  50.  
  51.     tcb->cwind = tcb->mss = Tcp_mss;
  52.     tcb->ssthresh = 65535;
  53.     tcb->srtt = Tcp_irtt;
  54.     /* Initialize timer intervals */
  55.     tcb->timer.start = tcb->srtt / MSPTICK;
  56.     tcb->timer.func = tcp_timeout;
  57.     tcb->timer.arg = (char *)tcb;
  58.  
  59.     link_tcb(tcb);
  60.     return tcb;
  61. }
  62.  
  63. /* Close our TCB */
  64. void
  65. close_self(tcb,reason)
  66. register struct tcb *tcb;
  67. int reason;
  68. {
  69.     struct reseq *rp1;
  70.     register struct reseq *rp;
  71.  
  72.     if(tcb == NULLTCB)
  73.         return;
  74.  
  75.     stop_timer(&tcb->timer);
  76.     tcb->reason = reason;
  77.  
  78.     /* Flush reassembly queue; nothing more can arrive */
  79.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  80.         rp1 = rp->next;
  81.         free_p(rp->bp);
  82.         free((char *)rp);
  83.     }
  84.     tcb->reseq = NULLRESEQ;
  85.     setstate(tcb,CLOSED);
  86. }
  87.  
  88. /* Sequence number comparisons
  89.  * Return true if x is between low and high inclusive,
  90.  * false otherwise
  91.  */
  92. int
  93. seq_within(x,low,high)
  94. register int32 x,low,high;
  95. {
  96.     if(low <= high){
  97.         if(low <= x && x <= high)
  98.             return 1;
  99.     } else {
  100.         if(low >= x && x >= high)
  101.             return 1;
  102.     }
  103.     return 0;
  104. }
  105. int
  106. seq_lt(x,y)
  107. register int32 x,y;
  108. {
  109.     return (long)(x-y) < 0;
  110. }
  111. int
  112. seq_le(x,y)
  113. register int32 x,y;
  114. {
  115.     return (long)(x-y) <= 0;
  116. }
  117. int
  118. seq_gt(x,y)
  119. register int32 x,y;
  120. {
  121.     return (long)(x-y) > 0;
  122. }
  123. int
  124. seq_ge(x,y)
  125. register int32 x,y;
  126. {
  127.     return (long)(x-y) >= 0;
  128. }
  129.  
  130. /* Hash a connect structure into the hash chain header array */
  131. static int16
  132. hash_tcb(conn)
  133. struct connection *conn;
  134. {
  135.     register unsigned int hval;
  136.  
  137.     /* Compute hash function on connection structure */
  138.     hval = hiword(conn->remote.address);
  139.     hval ^= loword(conn->remote.address);
  140.     hval ^= hiword(conn->local.address);
  141.     hval ^= loword(conn->local.address);
  142.     hval ^= conn->remote.port;
  143.     hval ^= conn->local.port;
  144.     return hval % NTCB;
  145. }
  146. /* Insert TCB at head of proper hash chain */
  147. void
  148. link_tcb(tcb)
  149. register struct tcb *tcb;
  150. {
  151.     register struct tcb **tcbhead;
  152.     char i_state;
  153.  
  154.     tcb->prev = NULLTCB;
  155.     i_state = dirps();
  156.     tcbhead = &Tcbs[hash_tcb(&tcb->conn)];
  157.     tcb->next = *tcbhead;
  158.     if(tcb->next != NULLTCB)
  159.         tcb->next->prev = tcb;
  160.  
  161.     *tcbhead = tcb;
  162.     restore(i_state);
  163. }
  164. /* Remove TCB from whatever hash chain it may be on */
  165. void
  166. unlink_tcb(tcb)
  167. register struct tcb *tcb;
  168. {
  169.     register struct tcb **tcbhead;
  170.     char i_state;
  171.  
  172.     i_state = dirps();
  173.     tcbhead = &Tcbs[hash_tcb(&tcb->conn)];
  174.     if(tcb->prev == NULLTCB)
  175.         *tcbhead = tcb->next;    /* We're the first one on the chain */
  176.     else
  177.         tcb->prev->next = tcb->next;
  178.     if(tcb->next != NULLTCB)
  179.         tcb->next->prev = tcb->prev;
  180.     restore(i_state);
  181. }
  182. void
  183. setstate(tcb,newstate)
  184. register struct tcb *tcb;
  185. register int newstate;
  186. {
  187.     register char oldstate;
  188.  
  189.     oldstate = tcb->state;
  190.     tcb->state = newstate;
  191.     if(Tcp_trace)
  192.         printf("TCB %lx %s -> %s\n",ptol(tcb),
  193.          Tcpstates[oldstate],Tcpstates[newstate]);
  194.     if(tcb->s_upcall)
  195.         (*tcb->s_upcall)(tcb,oldstate,newstate);
  196.  
  197.     switch(newstate){
  198.     case ESTABLISHED:
  199.         /* Notify the user that he can begin sending data */
  200.         if(tcb->t_upcall)
  201.             (*tcb->t_upcall)(tcb,tcb->window - tcb->sndcnt);
  202.         break;
  203.     }
  204. }
  205. /* Convert TCP header in host format into mbuf ready for transmission,
  206.  * link in data (if any), and compute checksum
  207.  */
  208. struct mbuf *
  209. htontcp(tcph,data,ph)
  210. register struct tcp *tcph;
  211. struct mbuf *data;
  212. struct pseudo_header *ph;
  213. {
  214.     int16 hdrlen;
  215.     struct mbuf *bp;
  216.     register char *cp;
  217.     int16 csum;
  218.  
  219.     hdrlen = (tcph->mss != 0) ? TCPLEN + MSS_LENGTH : TCPLEN;
  220.     
  221.     if((bp = pushdown(data,hdrlen)) == NULLBUF){
  222.         free_p(data);
  223.         return NULLBUF;
  224.     }
  225.     cp = bp->data;
  226.     cp = put16(cp,tcph->source);
  227.     cp = put16(cp,tcph->dest);
  228.     cp = put32(cp,tcph->seq);
  229.     cp = put32(cp,tcph->ack);
  230.     *cp++ = hdrlen << 2;    /* Offset field */
  231.     *cp = 0;
  232.     if(tcph->flags.urg)
  233.         *cp |= 32;
  234.     if(tcph->flags.ack)
  235.         *cp |= 16;
  236.     if(tcph->flags.psh)
  237.         *cp |= 8;
  238.     if(tcph->flags.rst)
  239.         *cp |= 4;
  240.     if(tcph->flags.syn)
  241.         *cp |= 2;
  242.     if(tcph->flags.fin)
  243.         *cp |= 1;
  244.     cp++;
  245.     cp = put16(cp,tcph->wnd);
  246.     *cp++ = 0;    /* Zero out checksum field */
  247.     *cp++ = 0;
  248.     cp = put16(cp,tcph->up);
  249.  
  250.     if(tcph->mss != 0){
  251.         *cp++ = MSS_KIND;
  252.         *cp++ = MSS_LENGTH;
  253.         cp = put16(cp,tcph->mss);
  254.     }
  255.     csum = cksum(ph,bp,ph->length);
  256.     /* Fill checksum field */    
  257.     put16(&bp->data[16],csum);
  258.  
  259.     return bp;
  260. }
  261. /* Pull TCP header off mbuf */
  262. int
  263. ntohtcp(tcph,bpp)
  264. register struct tcp *tcph;
  265. struct mbuf **bpp;
  266. {
  267.     int16 hdrlen;
  268.     int16 i,optlen;
  269.     register int flags;
  270.     char hdrbuf[TCPLEN];
  271.  
  272.     i = pullup(bpp,hdrbuf,TCPLEN);
  273.     /* Note that the results will be garbage if the header is too short.
  274.      * We don't check for this because returned ICMP messages will be
  275.      * truncated, and we at least want to get the port numbers.
  276.      */
  277.     tcph->source = get16(&hdrbuf[0]);
  278.     tcph->dest = get16(&hdrbuf[2]);
  279.     tcph->seq = get32(&hdrbuf[4]);
  280.     tcph->ack = get32(&hdrbuf[8]);
  281.     hdrlen = (hdrbuf[12] & 0xf0) >> 2;
  282.     flags = hdrbuf[13];
  283.     tcph->flags.urg = flags & 32;
  284.     tcph->flags.ack = flags & 16;
  285.     tcph->flags.psh = flags & 8;
  286.     tcph->flags.rst = flags & 4;
  287.     tcph->flags.syn = flags & 2;
  288.     tcph->flags.fin = flags & 1;
  289.     tcph->wnd = get16(&hdrbuf[14]);
  290.     tcph->up = get16(&hdrbuf[18]);
  291.     tcph->mss = 0;
  292.  
  293.     /* Check for option field. Only space for one is allowed, but
  294.      * since there's only one TCP option (MSS) this isn't a problem
  295.      */
  296.     if(i < TCPLEN || hdrlen < TCPLEN)
  297.         return -1;    /* Header smaller than legal minimum */
  298.     if(hdrlen == TCPLEN)
  299.         return hdrlen;    /* No options, all done */
  300.  
  301.     if(hdrlen > len_mbuf(*bpp) + TCPLEN){
  302.         /* Remainder too short for options length specified */
  303.         return -1;
  304.     }
  305.     /* Process options */
  306.     for(i=TCPLEN; i < hdrlen;){
  307.         switch(pullchar(bpp)){
  308.         case EOL_KIND:
  309.             i++;
  310.             goto eol;    /* End of options list */
  311.         case NOOP_KIND:
  312.             i++;
  313.             break;
  314.         case MSS_KIND:
  315.             optlen = pullchar(bpp);
  316.             if(optlen == MSS_LENGTH)
  317.                 tcph->mss = pull16(bpp);
  318.             i += optlen;
  319.             break;
  320.         }
  321.     }
  322. eol:
  323.     /* Get rid of any padding */
  324.     if(i < hdrlen)
  325.         pullup(bpp,NULLCHAR,hdrlen - i);
  326.     return hdrlen;
  327. }
  328.